﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Engine.Dtd {
    internal class EntityResolver {
        /// <summary>
        /// This is the windows-1252 mapping of the code points 0x80 through 0x9f.
        /// </summary>
        private static int[] ControlCarachtersMap = new int[] {
                                             8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141,
                                             381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 
                                             339, 157, 382, 376
                                         };
        /// <summary>
        /// Expands a character entity reference to be read from the input stream.
        /// </summary>
        /// <returns>The char for the character entity.</returns>
        public bool ResolveCharacterReference(EntityReader reader, out char ch) {
            int v = 0;
            ch = reader.ReadChar();
            if (ch == 'x') {
                ch = reader.ReadChar();
                while (ch != Characters.EndOfFile && ch != Characters.SemiColon) {
                    int p = 0;
                    if (ch >= '0' && ch <= '9')
                        p = (int)(ch - '0');
                    else if (ch >= 'a' && ch <= 'f')
                        p = (int)(ch - 'a') + 10;
                    else if (ch >= 'A' && ch <= 'F')
                        p = (int)(ch - 'A') + 10;
                    else
                        break;
                    v = (v * 16) + p;
                    if (v < char.MinValue || char.MaxValue < v)
                        return false;
                    ch = reader.ReadChar();
                    }
                }
            else
                while (ch != Characters.EndOfFile && ch != Characters.SemiColon) {
                    if (ch >= '0' && ch <= '9') {
                        v = (v * 10) + (int)(ch - '0');
                        if (v < char.MinValue || char.MaxValue < v)
                            return false;
                        }
                    else
                        break;
                    ch = reader.ReadChar();
                    }
            if (ch == 0)
                throw new DtdException(string.Format("Premature {0} parsing entity reference.", ch), reader.Context());
            if (ch == Characters.SemiColon)
                reader.ReadChar();

            // HACK ALERT: IE and Netscape map the unicode characters 
            // If entity is HTML document
            if (v >= 0x80 & v <= 0x9F)
                // This range of control characters is mapped to Windows-1252!
                ch = Convert.ToChar(ControlCarachtersMap[v - 0x80]);
            else
                ch = Convert.ToChar(v);
            return true;
            }
        }
    }
